package ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.imp;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.DeviceDAO;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.AddressType;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.AddressValue;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Alarm;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.CompoundCommand;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Device;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.DeviceType;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.Field;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.SimpleCommand;
import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.persistence.model.SoundRequest;

@Component
public class DeviceDAOImp implements DeviceDAO {

	private SessionFactory  sessionFactory;
	  
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
    
	@Autowired(required = true)
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	
	@Override
	public Device findDevice(Integer id) {
		try {
			Session session = sessionFactory.openSession();
			Object ret = session.get(Device.class, id);
			session.close();
			if(ret instanceof Device)
				return (Device) ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	
	@Override
	public List<Alarm> getAlarms(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			List<Alarm> ret = device.getType().getAlarms();
			Hibernate.initialize(ret);
			/*for (Alarm alarm : ret) {
				alarm.getID();
			}*/
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}
	
	@Override
	public List<CompoundCommand> getCompoundCommands(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			List<CompoundCommand> ret = device.getType().getCompoundCommands();
			Hibernate.initialize(ret);
			/*for (CompoundCommand compoundCommand : ret) {
				compoundCommand.getID();
			}*/
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@Override
	public List<SimpleCommand> getSimpleCommands(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			List<SimpleCommand> ret = device.getType().getSimpleCommands();
			Hibernate.initialize(ret);
			/*for (SimpleCommand simpleCommand : ret) {
				simpleCommand.getID();
			}*/
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@Override
	public List<Field> getFields(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			
			device = (Device) session.get(Device.class,device.getID());
			List<Field> ret = device.getType().getFields();
			Hibernate.initialize(ret);
			/*for (Field field : ret) {
				field.getID();
			}*/
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@Override
	public Date lastDateActivity(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			Date ret = device.getLastActivity();
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@Override
	public AddressValue getLastAddressValue(Device device, Integer address,
			AddressType addressType) {

		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			Criteria crit = session.createCriteria(AddressValue.class);
			crit.add(Restrictions.eq("device", device));
			crit.add(Restrictions.eq("address", address));
			crit.add(Restrictions.eq("addressType", addressType));
			crit.addOrder(Order.desc("date"));
			crit.setMaxResults(1);
			AddressValue ret = (AddressValue) crit.uniqueResult();
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){

		}
		return null;
	}


	@Override
	public void saveValue(Device device, Integer address, Integer value,
			AddressType addressType) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			AddressValue naddrs = new AddressValue();
			naddrs.setAddressType(addressType);
			naddrs.setAddress(address);
			naddrs.setDate(new Date());
			naddrs.setDevice(device);
			naddrs.setValue(value);
			device.getAddressValues().add(naddrs);
			
			tx.commit();
			session.close();
			return ;
		}
		catch(HibernateException e){
			
		}
		
	}

	@Override
	public void setLastActivity(Device device, Date date) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			device.setLastActivity(date);
			
			tx.commit();
			session.close();
			return ;
		}
		catch(HibernateException e){
			
		}
		
	}

	@Override
	public String getDeviceTypeName(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			String ret = device.getType().getName();
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@Override
	public Date getLastActivity(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			Date ret = device.getLastActivity();
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}


	@Override
	public List<SoundRequest> getSoundRequests(Device device) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx =  session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			List<SoundRequest> ret = device.getType().getSoundRequests();
			Hibernate.initialize(ret);
			/* for (SoundRequest soundRequest : ret) {
				soundRequest.getID();
			}*/
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void saveValues(Device device, List<AddressValue> addValues) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			device = (Device) session.get(Device.class,device.getID());
			
			for (AddressValue addressValue : addValues) {
				Criteria crit = session.createCriteria(AddressValue.class);
				crit.add(Restrictions.eq("device", device));
				crit.add(Restrictions.eq("address", addressValue.getAddress()));
				crit.add(Restrictions.eq("addressType", addressValue.getAddressType()));
				List<AddressValue> values = crit.list();
				if(values.size() == 0){
				    addressValue.setDevice(device);
				    device.getAddressValues().add(addressValue);
				}
				else {
					AddressValue value = values.get(0);
					value.setDate(addressValue.getDate());
					value.setValue(addressValue.getValue());
				}
			}
			
			tx.commit();
			session.close();
		}
		catch(HibernateException e){
			
		}
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<DeviceType> listDeviceTypes() {
		// TODO Auto-generated method stub
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			Criteria crit = session.createCriteria(DeviceType.class);
			crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
			List<DeviceType> ret = crit.list();
			for (DeviceType deviceType : ret) {
				Hibernate.initialize(deviceType.getFields());
				Hibernate.initialize(deviceType.getAlarms());
				Hibernate.initialize(deviceType.getSoundRequests());
				Hibernate.initialize(deviceType.getCompoundCommands());
				Hibernate.initialize(deviceType.getSimpleCommands());
			}
			tx.commit();
			session.close();
			return ret;
		}
		catch(HibernateException e){
			
		}
		return null;
	}

	@Override
	public void saveOrUpdateType(DeviceType type) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			session.saveOrUpdate(type);
			tx.commit();
			session.close();
		}
		catch(HibernateException e){
			
		}
		
	}

	@Override
	public void deleteType(DeviceType type) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			session.delete(type);
			tx.commit();
			session.close();
		}
		catch(HibernateException e){
			
		}
		
	}

	@Override
	public List<Device> listDevices() {
		// TODO Auto-generated method stub
				try {
					Session session = sessionFactory.openSession();
					Transaction tx = session.beginTransaction();
					Criteria crit = session.createCriteria(Device.class);
					crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
					@SuppressWarnings("unchecked")
					List<Device> ret = crit.list();
					for (Device device : ret) {
						Hibernate.initialize(device.getType());
					}
					tx.commit();
					session.close();
					return ret;
				}
				catch(HibernateException e){
					
				}
				return null;
	}

	@Override
	public void saveOrUpdateDevice(Device type) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			session.saveOrUpdate(type);
			tx.commit();
			session.close();
		}
		catch(HibernateException e){
			
		}
		
	}

	@Override
	public void deleteDevice(Device type) {
		try {
			Session session = sessionFactory.openSession();
			Transaction tx = session.beginTransaction();
			session.delete(type);
			tx.commit();
			session.close();
		}
		catch(HibernateException e){
			
		}
	}

}
